flag.hpp
namespace type_safe
{
class flag;
constexpr bool operator==(flag lhs, flag rhs) noexcept;
template <typename T>
constexpr bool operator==(flag lhs, T rhs) noexcept;
template <typename T>
constexpr bool operator==(T lhs, flag rhs) noexcept;
constexpr bool operator!=(flag lhs, flag rhs) noexcept;
template <typename T>
constexpr bool operator!=(flag lhs, T rhs) noexcept;
template <typename T>
constexpr bool operator!=(T lhs, flag rhs) noexcept;
}
type_safe::flag
[types]class flag
{
public:
flag() = delete;
template <typename T, typename = detail::enable_boolean<T>>
constexpr flag(T initial_state) noexcept;
bool toggle() noexcept;
template <typename T>
void change(T new_state) noexcept;
void set() noexcept;
bool try_set() noexcept;
void reset() noexcept;
bool try_reset() noexcept;
};
A type safe flag, it can either be true
or false
.
Consider the following snippet:
auto was_newl = false;
for (auto x : …)
{
if (x == '/n')
{
assert(!was_newl); // want to change value here
was_newl = true;
}
else if (was_newl)
{
do_sth(c);
was_newl = false; // separate step, easy to forget (I did here originally!)
}
}
With flag, it is better:
type_safe::flag was_newl(false);
for (auto x : …)
{
if (x == '/n')
was_newl.change(true); // asserts that value is changed
else if (was_newl.try_reset()) // resets flag and returns whether value changed
do_sth(x); // no way to forget
}
Notes: It is named flag
for consistency with std::atomic_flag, even though this one can provide an extended interface as it is not atomic. flag
has nothing to do with ts::flag_set.
type_safe::flag::flag
template <typename T, typename = detail::enable_boolean<T>>
constexpr flag(T initial_state) noexcept;
Effects: Gives the flag the initial state.
Notes: This function does not participate in overload resolution if T
is not a boolean type. \param 1 \exclude
type_safe::flag::toggle
bool toggle() noexcept;
Effects: Flips the state of the flag.
Returns: The old value.
type_safe::flag::change
template <typename T>
void change(T new_state) noexcept;
Effects: Sets its state to the new one.
Requires: The new state must be different than the old one.
type_safe::flag::set
void set() noexcept;
Effects: Sets its state to true
.
type_safe::flag::try_set
bool try_set() noexcept;
Effects: Sets its state to true
.
Returns: true
if the previous state was false
, false
otherwise, i.e. whether or not the state was changed.
type_safe::flag::reset
void reset() noexcept;
Effects: Sets its state to false
.
type_safe::flag::try_reset
bool try_reset() noexcept;
Effects: Sets its state to false
.
Returns: true
if the previous state was true
, false
otherwise, i.e. whether or not the state was changed.
type_safe::operator==
[types](1) constexpr bool operator==(flag lhs, flag rhs) noexcept;
(2) template <typename T>
constexpr bool operator==(flag lhs, T rhs) noexcept;
(3) template <typename T>
constexpr bool operator==(T lhs, flag rhs) noexcept;
ts::flag equality comparison.
Returns: true
if (1) both ts::flag objects are in the same state, (2)/(3) the flag is in the given state.
Notes: (2)/(3) do not participate in overload resolution unless T
is a boolean type.
type_safe::operator!=
[types](1) constexpr bool operator!=(flag lhs, flag rhs) noexcept;
(2) template <typename T>
constexpr bool operator!=(flag lhs, T rhs) noexcept;
(3) template <typename T>
constexpr bool operator!=(T lhs, flag rhs) noexcept;
ts::flag in-equality comparison.
Returns: true
if (1) both ts::flag objects are in the same state, (2)/(3) the flag is in the given state.
Notes: (2)/(3) do not participate in overload resolution unless T
is a boolean type.